﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace HMaker.Utils
{
    public static class BitmapUtils
    {
        /// <summary>
        /// 从字节码创建位图对象
        /// </summary>
        /// <returns></returns>
        public static Bitmap FromBytes(byte[] bytes)
        {
            if (bytes == null)
            {
                return null;
            }
            try
            {
                return new Bitmap(new MemoryStream(bytes));
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 放大一个位图,将每一个像素纵横等量放大scalar倍
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="scalar"></param>
        /// <returns>处理后的图片,但是这个图片仅用于展示,不用于存储</returns>
        public static Bitmap Enlarge(Bitmap srcBitmap, int scalar)
        {
            if (scalar <= 1) { return (Bitmap)srcBitmap.Clone(); }
            int orginW = srcBitmap.Size.Width, orginH = srcBitmap.Size.Height, newW = orginW * scalar, newH = orginH * scalar;
            BitmapData srcBitmapData = srcBitmap.LockBits(new Rectangle(Point.Empty, srcBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Bitmap bitmap = new Bitmap(newW, newH);
            BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            unsafe
            {
                uint* srcbyte = (uint*)srcBitmapData.Scan0.ToPointer();
                uint* dstbyte = (uint*)bitmapData.Scan0.ToPointer();
                for (int y = 0; y < orginH; y++)
                {
                    for (int x = 0; x < orginW; x++)
                    {
                        for (int i = 0; i < scalar; i++)
                        {
                            *dstbyte++ = *srcbyte;
                        }
                        ++srcbyte;
                    }
                    uint* dstbyte2 = dstbyte - newW;
                    for (int i = 1; i < scalar; i++)
                    {
                        for (int j = 0; j < newW; j++)
                        {
                            *dstbyte++ = *dstbyte2++;
                        }
                    }
                }
            }
            srcBitmap.UnlockBits(srcBitmapData);
            bitmap.UnlockBits(bitmapData);
            return bitmap;
        }

        /// <summary>
        /// 将一张位图按照某个点为新图片的中心点,进行按倍数放大
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="dstBitmap"></param>
        /// <param name="srcPoint"></param>
        /// <param name="blankColor">空白颜色</param>
        /// <param name="scalar">只能为奇数</param>
        /// <returns>返回<paramref name="dstBitmap"/></returns>
        public static Bitmap Enlarge(this Bitmap srcBitmap, Bitmap dstBitmap, Point srcPoint, Color blankColor, int scalar)
        {

            unsafe
            {
                //横向要求的像素点个数
                int requireX = (int)Math.Ceiling((double)dstBitmap.Width / scalar);
                int requireY = (int)Math.Ceiling((double)dstBitmap.Height / scalar);


                int srcW = requireX / 2;
                int srcH = requireY / 2;
                Rectangle rect = Rectangle.FromLTRB(
                    srcPoint.X - srcW,
                    srcPoint.Y - srcH,
                    srcPoint.X + srcW + 1,
                    srcPoint.Y + srcH + 1
                );

                Rectangle lockRect = new Rectangle(Point.Empty, srcBitmap.Size);
                lockRect.Intersect(rect);

                BitmapData srcData = null;
                BitmapData dstData = null;
                try
                {
                    srcData = srcBitmap.LockBits(new Rectangle(Point.Empty, srcBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                    dstData = dstBitmap.LockBits(new Rectangle(Point.Empty, dstBitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

                    uint* srcPtr = (uint*)srcData.Scan0.ToPointer() + lockRect.Y * srcData.Width; //指针预先指向要被裁剪的第一行
                    uint* dstPtr = (uint*)dstData.Scan0.ToPointer();

                    Debug.Assert(dstBitmap.Width % 2 == 1, "目标图片宽度必须为奇数");
                    Debug.Assert(dstBitmap.Height % 2 == 1, "目标图片高度必须为奇数");

                    int firstW = (dstBitmap.Width - scalar) / 2 % scalar;
                    int firstH = (dstBitmap.Width - scalar) / 2 % scalar;

                    //重复写入单个像素
                    void repeatWrite(uint data, int count)
                    {
                        while (count-- > 0)
                            *dstPtr++ = data;
                    }

                    //写入一个新的行
                    void writeNewLine()
                    {
                        srcPtr += lockRect.Left;
                        int lockWidth = lockRect.Width;
                        if (rect.Left < 0)
                        {
                            repeatWrite(0XFFFF00FF, firstW + (-rect.Left - 1) * scalar);
                        }
                        else
                        {
                            --lockWidth;
                            repeatWrite(*srcPtr++, firstW);
                        }

                        for (int j = lockWidth - 1; j > 0; j--)
                        {
                            repeatWrite(*srcPtr++, scalar);
                        }

                        if (rect.Right > srcBitmap.Width)
                        {
                            //如果超出边界,需要补充
                            repeatWrite(0xFFFF00FF, firstW + (rect.Right - srcBitmap.Width - 1) * scalar);
                        }
                        else
                        {
                            repeatWrite(*srcPtr++, firstW);
                            srcPtr += (srcBitmap.Width - rect.Right);
                        }
                    }

                    //重复上一行的内容
                    void repeatWriteLine(int count)
                    {
                        while (count-- > 0)
                        {
                            int length = dstData.Width;
                            uint* lastPtr = dstPtr - length;
                            while (length-- > 0)
                                *dstPtr++ = *lastPtr++;
                        }
                    }


                    int lockHeight = lockRect.Height;
                    //处理上边界
                    if (rect.Top < 0)
                    {
                        repeatWrite(0xFFFF00FF, dstData.Width);
                        repeatWriteLine(firstH - 1);
                        for (int i = -rect.Y - 1; i > 0; i--)
                        {
                            repeatWriteLine(scalar);
                        }
                    }
                    else
                    {
                        --lockHeight;
                        writeNewLine();
                        repeatWriteLine(firstH - 1);
                    }

                    //处理中间内容
                    for (int i = lockHeight - 1; i > 0; i--)
                    {
                        writeNewLine();
                        repeatWriteLine(scalar - 1);
                    }

                    //处理下边界
                    if (rect.Bottom > srcBitmap.Height)
                    {
                        repeatWrite(0xFFFF00FF, dstData.Width);
                        repeatWriteLine(firstH - 1);
                        for (int i = rect.Bottom - srcBitmap.Height; i > 0; i--)
                        {
                            repeatWriteLine(scalar);
                        }
                    }
                    else
                    {
                        writeNewLine();
                        repeatWriteLine(firstH - 1);
                    }
                }
                finally
                {
                    srcBitmap.UnlockBits(srcData);
                    dstBitmap.UnlockBits(dstData);
                }

                return dstBitmap;
            }
        }

        /// <summary>
        /// 对图片进行裁剪,返回裁剪后的图片
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="srcRect"></param>
        /// <returns></returns>
        public static Bitmap Clip(Bitmap srcBitmap, Rectangle srcRect)
        {
            if (srcRect.Width == 0 || srcBitmap.Height == 0)
            {
                return null;
            }

            srcRect.Width++;
            srcRect.Height++;
            if (srcRect.Left < 0)
            {
                srcRect.X = 0;
            }
            if (srcRect.Right > srcBitmap.Width)
            {
                if (srcBitmap.Width > srcRect.X)
                {
                    srcRect.Width = srcBitmap.Width - srcRect.X;
                }
                else
                {
                    return null;
                }
            }

            if (srcRect.Top < 0)
            {
                srcRect.Y = 0;
            }
            if (srcRect.Bottom > srcBitmap.Height)
            {
                if (srcBitmap.Height > srcRect.Y)
                {
                    srcRect.Height = srcBitmap.Height - srcRect.Y;
                }
                else
                {
                    return null;
                }
            }
            return srcBitmap.Clone(srcRect, PixelFormat.Format24bppRgb);
        }

        /// <summary>
        /// 将图片中的srcColor颜色替换为dstColor
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="srcColor"></param>
        /// <param name="dstColor"></param>
        /// <returns></returns>
        public static Bitmap ReplaceColor(Bitmap srcBitmap, Color srcColor, Color dstColor)
        {
            Rectangle srcRect = new Rectangle(Point.Empty, srcBitmap.Size);
            BitmapData srcBitmapData = srcBitmap.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Bitmap bitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height);
            BitmapData bitmapData = bitmap.LockBits(srcRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            uint srcColorByte = (uint)srcColor.ToArgb();
            uint dstColorByte = (uint)dstColor.ToArgb();
            int size = srcBitmap.Width * srcBitmap.Height;
            unsafe
            {
                uint* srcPointer = (uint*)srcBitmapData.Scan0.ToPointer();
                uint* dstPointer = (uint*)bitmapData.Scan0.ToPointer();
                for (int i = 0; i < size; i++)
                {
                    *dstPointer++ = *srcPointer == srcColorByte ? dstColorByte : *srcPointer;
                    ++srcPointer;
                }
            }
            srcBitmap.UnlockBits(srcBitmapData);
            bitmap.UnlockBits(bitmapData);
            Bitmap result = bitmap.Clone(srcRect, PixelFormat.Format24bppRgb);
            bitmap.Dispose();
            return result;
        }


        /// <summary>
        /// 将制定位置的像素替换后返回新图片
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="point"></param>
        /// <param name="dstColor"></param>
        /// <returns></returns>
        public static Bitmap ReplaceColor(Bitmap srcBitmap, Point point, Color dstColor)
        {
            Rectangle srcRect = new Rectangle(Point.Empty, srcBitmap.Size);
            Bitmap result = srcBitmap.Clone(srcRect, PixelFormat.Format24bppRgb);
            result.SetPixel(point.X, point.Y, dstColor);
            return result;
        }

        /// <summary>
        /// 将图片中的srcColor(semblance)颜色替换为指定的颜色
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="srcColor"></param>
        /// <param name="semblance"></param>
        /// <param name="dstColor"></param>
        /// <param name="isDirectSelect"></param>
        /// <returns></returns>
        public static Bitmap ReplaceColor(Bitmap srcBitmap, Color srcColor, double semblance, Color dstColor, bool isDirectSelect = false)
        {
            Rectangle srcRect = new Rectangle(Point.Empty, srcBitmap.Size);
            BitmapData srcBitmapData = srcBitmap.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Bitmap bitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height);
            BitmapData bitmapData = bitmap.LockBits(srcRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            srcColor.MakeRange(semblance, out Color minSrcColor, out Color maxSrcColor);
            uint minSrcColorByte = (uint)minSrcColor.ToArgb();
            uint maxSrcColorByte = (uint)maxSrcColor.ToArgb();

            uint dstColorByte = (uint)dstColor.ToArgb();
            int size = srcBitmap.Width * srcBitmap.Height;
            unsafe
            {
                uint* srcPointer = (uint*)srcBitmapData.Scan0.ToPointer();
                uint* dstPointer = (uint*)bitmapData.Scan0.ToPointer();

                if (isDirectSelect)
                {
                    for (int i = 0; i < size; i++)
                    {
                        *dstPointer++ = Util.CheckColorInRange(*srcPointer, minSrcColorByte, maxSrcColorByte) ? dstColorByte : *srcPointer;
                        ++srcPointer;
                    }
                }
                else
                {
                    for (int i = 0; i < size; i++)
                    {
                        *dstPointer++ = Util.CheckColorInRange(*srcPointer, minSrcColorByte, maxSrcColorByte) ? *srcPointer : dstColorByte;
                        ++srcPointer;
                    }
                }
            }
            srcBitmap.UnlockBits(srcBitmapData);
            bitmap.UnlockBits(bitmapData);
            Bitmap result = bitmap.Clone(srcRect, PixelFormat.Format24bppRgb);
            bitmap.Dispose();
            return result;
        }


        /// <summary>
        /// 在图片中匹配出相应的颜色,并返回一张二值图片,为透明色和dstColor两种颜色组成的图片,可将此图片重写于界面上,以达到标记位置的作用
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="srcColor"></param>
        /// <param name="semblance"></param>
        /// <param name="dstColor"></param>
        /// <returns>输出图片用于展示,故不考虑其格式</returns>
        public static Bitmap FindColors(Bitmap srcBitmap, Color srcColor, double semblance, Color dstColor, bool isDirectSelect = false)
        {
            Rectangle srcRect = new Rectangle(Point.Empty, srcBitmap.Size);
            BitmapData srcBitmapData = srcBitmap.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Bitmap bitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height);
            BitmapData bitmapData = bitmap.LockBits(srcRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            srcColor.MakeRange(semblance, out Color minSrcColor, out Color maxSrcColor);
            uint minSrcColorByte = (uint)minSrcColor.ToArgb();
            uint maxSrcColorByte = (uint)maxSrcColor.ToArgb();
            uint dstColorByte = (uint)dstColor.ToArgb();
            int size = srcBitmap.Width * srcBitmap.Height;

            unsafe
            {
                uint* srcPointer = (uint*)srcBitmapData.Scan0.ToPointer();
                uint* dstPointer = (uint*)bitmapData.Scan0.ToPointer();

                if (isDirectSelect)
                {
                    for (int i = 0; i < size; i++)
                    {
                        *dstPointer++ = Util.CheckColorInRange(*srcPointer++, minSrcColorByte, maxSrcColorByte) ? dstColorByte : 0;
                    }
                }
                else
                {
                    for (int i = 0; i < size; i++)
                    {
                        *dstPointer++ = Util.CheckColorInRange(*srcPointer++, minSrcColorByte, maxSrcColorByte) ? 0 : dstColorByte;
                    }
                }

            }
            srcBitmap.UnlockBits(srcBitmapData);
            bitmap.UnlockBits(bitmapData);
            return bitmap;
        }

        /// <summary>
        /// 获取一个颜色,并确保这个颜色与图片上的任意一个像素都不冲突
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <param name="deletaColor"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool FindCollisionlessColor(Bitmap srcBitmap, double similarly, out Color result, int retryCount = 3)
        {
            BitmapData srcBitmapData = srcBitmap.LockBits(new Rectangle(Point.Empty, srcBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            int size = srcBitmap.Width * srcBitmap.Height;
            try
            {
                unsafe
                {
                    bool Check(uint* p, uint minSrcColorByte, uint maxSrcColorByte)
                    {
                        for (int j = 0; j < size; j++)
                        {
                            if (!Util.CheckColorInRange(*p++, minSrcColorByte, maxSrcColorByte))
                            {
                                return false;
                            }
                        }
                        return true;
                    }

                    uint* srcPointer = (uint*)srcBitmapData.Scan0.ToPointer();
                    for (int i = 0; i < retryCount; i++)
                    {
                        Color color = Util.GetRamdomColor();
                        color.MakeRange(similarly, out Color minColor, out Color maxColor);
                        uint minSrcColorByte = (uint)maxColor.ToArgb();
                        uint maxSrcColorByte = (uint)maxColor.ToArgb();

                        if (!Check(srcPointer, (uint)minColor.ToArgb(), (uint)maxColor.ToArgb()))
                        {
                            result = color;
                            return true;
                        }
                    }
                    result = Color.Empty;
                    return false;
                }
            }
            finally
            {
                srcBitmap.UnlockBits(srcBitmapData);
            }
        }


        //public static Bitmap ComparePic(Bitmap firstBitmap, Bitmap secondBitmap)
        //{
        //    BitmapData firstBitmapData = firstBitmap.LockBits(new Rectangle(Point.Empty, firstBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        //    BitmapData secondBitmapData = secondBitmap.LockBits(new Rectangle(Point.Empty, secondBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        //    Bitmap bitmap = new Bitmap(firstBitmap.Width, firstBitmap.Height);
        //    BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        //    int size = firstBitmap.Width * firstBitmap.Height;
        //    unsafe
        //    {
        //        uint* firstPointer = (uint*)firstBitmapData.Scan0.ToPointer();
        //        uint* secondPointer = (uint*)secondBitmapData.Scan0.ToPointer();
        //        uint* dstPointer = (uint*)bitmapData.Scan0.ToPointer();
        //        for (int i = 0; i < size; i++)
        //        {
        //            *dstPointer++ = (*firstPointer) == (*secondPointer) ? *firstPointer : (uint)Color.White.ToArgb();
        //            ++firstPointer;
        //            ++secondPointer;

        //            //Console.WriteLine(*firstPointer == (*secondPointer) ? (uint)Color.White.ToArgb() : *firstPointer);
        //            //Console.WriteLine(*firstPointer + " " + *secondPointer + " " + *dstPointer);
        //        }
        //    }
        //    firstBitmap.UnlockBits(firstBitmapData);
        //    secondBitmap.UnlockBits(secondBitmapData);
        //    bitmap.UnlockBits(bitmapData);
        //    return bitmap;
        //}


        /// <summary>
        /// 自动将图片四周的作为透明色的区域裁减掉
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <returns></returns>
        public static Bitmap AutoClip(Bitmap srcBitmap)
        {
            //FIXME:去除空白算法有误
            BitmapData srcBitmapData = srcBitmap.LockBits(new Rectangle(Point.Empty, srcBitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Rectangle clipRect = Rectangle.Empty;
            try
            {
                int w = srcBitmap.Width, h = srcBitmap.Height;
                unsafe
                {
                    /// <summary>
                    /// 比较指定一行的像素点是否等于color
                    /// </summary>
                    /// <param name="color"></param>
                    /// <param name="srcPoint"></param>
                    /// <param name="width"></param>
                    /// <param name="y"></param>
                    /// <returns></returns>
                    bool _CmpRowColor(uint color, uint* srcPoint, int width, int y)
                    {
                        uint* point = srcPoint + (width * y);
                        for (int x = 0; x < width; x++)
                        {
                            if (color != *point++)
                            {
                                return false;
                            }
                        }
                        return true;
                    }

                    /// <summary>
                    /// 比较指定一列的像素点是否等于color
                    /// </summary>
                    /// <param name="color"></param>
                    /// <param name="srcPointer"></param>
                    /// <param name="width"></param>
                    /// <param name="height"></param>
                    /// <param name="x"></param>
                    /// <returns></returns>
                    bool _CmpColumnColor(uint color, uint* srcPointer, int width, int height, int x)
                    {
                        uint* point = srcPointer + x;
                        for (int y = 0; y < height; y++)
                        {
                            if (color != *point)
                            {
                                return false;
                            }
                            point += width;
                        }
                        return true;
                    }

                    uint* srcbyte = (uint*)srcBitmapData.Scan0.ToPointer();
                    uint transparentColor = srcbyte[0];

                    //判断是否为透明图
                    if (transparentColor != srcbyte[w - 1] || transparentColor != srcbyte[w * (h - 1)] || transparentColor != srcbyte[w * h - 1])
                    {
                        return null;
                    }

                    //判断图片是否可能进行裁剪
                    if (h <= 2 || w <= 2)
                    {
                        return null;
                    }

                    int t = 0, b = h - 1, l = 0, r = w - 1;


                    //处理上边界
                    while (t < b)
                    {
                        if (!_CmpRowColor(transparentColor, srcbyte, w, t))
                        {
                            break;
                        }
                        ++t;
                        //检查端点
                        if (srcbyte[t * w] != transparentColor || srcbyte[(t + 1) * w - 1] != transparentColor)
                        {
                            --t;
                            break;
                        }
                    }

                    //处理下边界
                    while (b > t)
                    {
                        if (!_CmpRowColor(transparentColor, srcbyte, w, b))
                        {
                            break;
                        }
                        --b;
                        //检查端点
                        if (srcbyte[b * w] != transparentColor || srcbyte[(b + 1) * w - 1] != transparentColor)
                        {
                            ++b;
                            break;
                        }

                    }

                    //处理左边界
                    while (l < r)
                    {
                        if (!_CmpColumnColor(transparentColor, srcbyte, w, h, l))
                        {
                            break;
                        }
                        ++l;
                        //检查端点
                        if (srcbyte[t * w + l] != transparentColor || srcbyte[b * w + l] != transparentColor)
                        {
                            --l;
                            break;
                        }
                    }

                    //处理右边界
                    while (r > l)
                    {
                        if (!_CmpColumnColor(transparentColor, srcbyte, w, h, r))
                        {
                            break;
                        }
                        --r;
                        //检查端点
                        if (srcbyte[t * w + r] != transparentColor || srcbyte[b * w + r] != transparentColor)
                        {
                            ++r;
                            break;
                        }
                    }
                    if (l == r || t == b)
                    {
                        //如果全为透明则直接无法裁剪
                        return null;
                    }
                    clipRect = Rectangle.FromLTRB(l, t, r, b);
                }
            }
            finally
            {
                srcBitmap.UnlockBits(srcBitmapData);
            }
            return Clip(srcBitmap, clipRect);
        }

        /// <summary>
        /// 传入等量放大后的图片中的坐标,返回这个坐标在原图片中的位置
        /// </summary>
        /// <param name="largeBitmapPoint"></param>
        /// <param name="scalar"></param>
        /// <returns></returns>
        public static Point PointToOrgin(Point largeBitmapPoint, int scalar)
        {
            return new Point(largeBitmapPoint.X / scalar, largeBitmapPoint.Y / scalar);
        }

        /// <summary>
        /// 克隆指定的位图为24位的位图
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap CloneAs24bppRgbBmp(Bitmap bitmap)
        {
            return bitmap.PixelFormat == PixelFormat.Format24bppRgb ? bitmap : bitmap.Clone(new Rectangle(Point.Empty, bitmap.Size), PixelFormat.Format24bppRgb);
        }

        /// <summary>
        /// 保存图片到指定路径
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="file"></param>
        public static void SaveBitmap(Bitmap bitmap, string file)
        {
            using (Bitmap tmp = new Bitmap(bitmap).Clone(new Rectangle(Point.Empty, bitmap.Size), PixelFormat.Format24bppRgb))
            {
                tmp.Save(file, ImageFormat.Bmp);
            }
        }

        /// <summary>
        /// 将一个位图对象转换成byte数组
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static byte[] ToBytes(this Bitmap bitmap)
        {
            byte[] ret;
            using (MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Bmp);
                ret = ms.ToArray();
            }
            return ret;
        }
    }
}
